#include "libutil.hpp"

#include <iostream>
#include <stdlib.h>

using namespace std; 
const bool DEBUG_TIMER = true;

//=====================================================================
class Test 
{
private:
  int testCount;
  int val;

public:
  Test () { 
    this->val = 0;
    this->testCount = 0; 
    cout << "Created Test" << endl;
  };
  void plus (void) { this->testCount++; } ;
  void minus (void) { this->testCount--; } ;  
  void set (int n) { this->val = n; };
  int get (void) { return this->val; };
};

struct test_data
{
  char  key[128];
  int v;
};

//=====================================================================
bool
testListClass (void)
{
  List<Test> mage;
  Test * t;
  t = mage.alloc ();
  return true;
};

//=====================================================================
bool
testPTreeClass (void)
{
  Table<Test> * hoge;
  // hoe = new PTree<Test>;
  hoge = new Hash<Test> (100);
  struct test_data testData[] =
    {
      {"quiz", 1},
      {"first", 2},
      {"enemy", 3},
      {"dark", 4},
      {"white devil", 5},
      {"final answer", 6},
      {"frederica", 7},
      {"DAAAAAAAAAA!", 8},
      {"801", 9},
      {"HANASE!", 10},
      {"", 0}
    }, * p, * q;
      
  Test * t;

  cout << endl;
  debug (true, "INSERT TEST =============================");
  for (p = testData; p->v > 0; p++)
    {
      t = hoge->fetch ((void*)p->key, strlen (p->key));
      t->set (p->v);
      debug (true, "set \"%s\" (%d)", p->key, p->v);      
    }

  cout << endl;
  debug (true, "LOOKUP TEST =============================");
  for (p = testData; p->v > 0; p++)
    {
      t = hoge->lookup ((void*)p->key, strlen (p->key));
      debug (true, "get \"%s\" (%d) = %s", p->key, t->get (), (t->get () == p->v ? "OK" : "NG"));
    }

  cout << endl;

  debug (true, "FOREACH TEST ============================");
  int i = 0;
  for (hoge->feInit (); ! hoge->feEnd (); hoge->feNext ())
    {
      t = hoge->feGet ();
      i++;
      debug (true, "get \"%d\" %d/%d", t->get (), i, hoge->getCount ());
    }
  cout << (i == hoge->getCount () ? "OK" : "NG") << endl;

  cout <<  endl;
  debug (true, "REMOVE TEST =============================");
  for (p = testData; p->v > 0; p++)
    {
      if (hoge->remove ((void*)p->key, strlen (p->key)))
	debug (true, "Remove success \"%s\"", p->key);

      for (q = testData; q->v > 0; q++)
	{
	  if (NULL == (t = hoge->lookup ((void*)q->key, strlen (q->key))))
	    debug (true, "FAIL to get \"%s\"", q->key);
	  else
	    debug (true, "get \"%s\" (%d) = %s", q->key, t->get (), (t->get () == q->v ? "OK" : "NG"));
	}
    }

  return true;
}

void
testFunc (void * obj)
{
  debug (true, "%s", (char*)obj);
}



//=====================================================================
bool
testTimerClass (void)
{
  Timer t ;
  TimerNode * node;
  struct test_data testData[] =
    {
      {"itumo doorino aruhino koto ", 1},
      {"kimiha totsuzen tatiagari itta ", 2},
      {"konnya hoshi wo mini ikou ", 3},
      {"tamaniha iikoto iundane ", 5},
      {"akarimo nai michi wo ", 5},
      {"baka mitaini hasyaide aruita ", 5},
      {"makkurona sekaikara miageta ", 5},
      {"yozora ha hosi ga huru youde ", 5},
      {"itukara darou kiminokotowo ", 5},
      {"oikakeru watasiga ita ", 5},
      {"natsukasii anohino kesikiha ", 10},
      {"haiirono tsuchinositani kieta ", 10},
      {"togabitoha sono tumini kidukadu ", 10},
      {"nakusita sintakuwo yadosita konomiha ", 10},
      {"wasurenai orokoana hitono kiseki wo ", 10},
      {"mamorerunara sarimashou ", 10},

      {"", 0}
    }, * p;

  for (p = &testData[0]; p->v > 0; p++)
    {
      node = t.setTimer (testFunc, (void*) p->key, p->v);
      debug (DEBUG_TIMER, "Insert to timer (%d) : %s ", p->v, p->key);
      if (rand () % 4 != 0)
	{
	  debug (DEBUG_TIMER, "but DELETE");
	  node->disable ();
	}
    }

  for (int i = 0; i < 3000; i++)
    {
      usleep (10000);
      t.proc ();
    }

  return true;
}

//=====================================================================
bool
testBufferClass (void)
{
  Timer t ;
  struct test_data testData[] =
    {
      {"itumo doorino aruhino koto ", 1},
      {"kimiha totsuzen tatiagari itta ", 2},
      {"konnya hoshi wo mini ikou ", 3},
      {"tamaniha iikoto iundane ", 5},
      {"akarimo nai michi wo ", 5},
      {"baka mitaini hasyaide aruita ", 5},
      {"makkurona sekaikara miageta ", 5},
      {"yozora ha hosi ga huru youde ", 5},
      {"itukara darou kiminokotowo ", 5},
      {"oikakeru watasiga ita ", 5},
      {"natsukasii anohino kesikiha ", 10},
      {"haiirono tsuchinositani kieta ", 10},
      {"togabitoha sono tumini kidukadu ", 10},
      {"nakusita sintakuwo yadosita konomiha ", 10},
      {"wasurenai orokoana hitono kiseki wo ", 10},
      {"mamorerunara sarimashou ", 10},

      {"", 0}
    }, * ptr;

  Buffer buf1, buf2;
  byte_t * p;
  unsigned int len;
  unsigned int totalLen = 0;
  char result [0xfff];

  for (ptr = &(testData[0]); ptr->v > 0; ptr++)
    {
      buf1.write ((byte_t*)(&ptr->key[0]), strlen (ptr->key));
      totalLen += strlen (ptr->key);
    }

  assert (NULL != (p = buf1.fetch (&len)));
  assert (totalLen == len);

  memcpy (result, p, len);
  result [len] = '\0';

  debug (true, "OUTOUT: %s", result);;
  debug (true, "OK\n");

  
  u_int32_t seq = 0;
  for (ptr = &(testData[0]); ptr->v > 0; ptr++)
    {
      buf2.write ((byte_t*)(&ptr->key[0]), strlen (ptr->key), seq);
      totalLen += strlen (ptr->key);
      seq += 1;
    }

  assert (NULL != (p = buf2.fetch (&len)));

  memcpy (result, p, len);
  result [len] = '\0';

  debug (true, "OUTOUT: %s", result);;
  debug (true, "OK\n");

  return true;
}

bool 
testPreferenceClass (int argc, char *argv[])
{
  Preference pref;

  pref.define ("r", "proc.read_file", true,  PrefDef::PT_STR, "", "Pcap format file");
  pref.define ("i", "proc.interface", false, PrefDef::PT_STR, "", "Network Interface");
  pref.define ("a", "music.append",   false,  PrefDef::PT_BOOL, "false", "Music is available");
  pref.define ("c", "music.compress", false,  PrefDef::PT_BOOL, "false", "Compress export music");
  pref.define ("com", "music.compress", false,  PrefDef::PT_BOOL, "false", "Compress export music");
  pref.define ("iris", "music.compress", false,  PrefDef::PT_BOOL, "false", "Compress export music");

  if (! pref.import (argc, argv))
    {
      cerr << "ERROR: " << pref.getError () << endl;
      return false;
    }

  return true;
}


int
main (int argc, char *argv[])
{
  time_t t = time (NULL);
  srand ((unsigned int)t);
  cout <<  "Test PTree Class: " << (testPTreeClass() ? "OK" : "NG") << endl;
  // cout <<  "Test List Class: "  << (testListClass()  ? "OK" : "NG") << endl;
  // cout <<  "Test Timer Class: "  << (testTimerClass()  ? "OK" : "NG") << endl;
  // cout <<  "Test Buffer Class: "  << (testBufferClass()  ? "OK" : "NG") << endl;
  // cout <<  "Test Preference Class: "  << (testPreferenceClass(argc, argv)  ? "OK" : "NG") << endl;
  return 0;
}
